Example pair
D_T8_C1R2_1 D_T8_C1R2_2 D_T8_C1R2_5-95_1_2
list_images <- tibble(
image_name = c("D_T8_C1R2_1", "D_T8_C1R2_2", "D_T8_C1R2_5-95_1_2"),
folder_original = rep(paste0(folder_main, "check/D-00-original/"), 3),
folder_green = rep(paste0(folder_main, "example/"), 3),
folder_green_rolled = rep(paste0(folder_main, "example/"), 3),
folder_green_watershed = rep(paste0(folder_main, "example/"), 3),
folder_green_feature = rep(paste0(folder_main, "example/"), 3),
folder_green_cluster = rep(paste0(folder_main, "example/"), 3)
)
i = 3
image_name <- list_images$image_name[i]
folder_original <- list_images$folder_original[i]
folder_green <- list_images$folder_green[i]
# folder_red <- list_images$folder_red[i]
# folder_blue <- list_images$folder_blue[i]
folder_green_rolled <- list_images$folder_green_rolled[i]
folder_green_watershed <- list_images$folder_green_watershed[i]
folder_green_feature <- list_images$folder_green_feature[i]
0. original image
image_original <- readImage(paste0(folder_original, image_name, ".tiff"))
writeImage(image_original, paste0(folder_green, image_name, "-00-original.tiff"))
display(image_original, method = "raster")

1. Green channel
temp <- image_original
colorMode(temp) = Grayscale
image_green <- temp[,,2]
writeImage(image_green, paste0(folder_green, image_name, "-01-green.tiff"))
display(image_green, method = "raster")

2. Rolling ball
Python code from rolling_ball.py
py$file_green <- paste0(folder_green, image_name, ".tiff")
py$file_green_rolled <- paste0(folder_green_rolled, image_name, "-02-rolled.tiff")
The R variables should be passed to python but somehow failed. Not
sure where the problem is from, probably reticualte. 20220902 use the
externally generated rolled images.
import imageio
import os
import sys
import skimage
from skimage import data, restoration, util, io, color
def rolling_ball_light(image):
# 2. invert the image
image_inverted = util.invert(image)
# 3. rolling ball
background_inverted = restoration.rolling_ball(image_inverted, radius = 80, num_threads = 10)
# 4. invert the result
image_rolled_inverted = image_inverted - background_inverted
image_rolled = util.invert(image_rolled_inverted)
return image_rolled
image = io.imread(file_green)
NameError: name 'file_green' is not defined
image_rolled = rolling_ball_light(image)
NameError: name 'image' is not defined
io.imsave(file_green_rolled, image_rolled)
NameError: name 'file_green_rolled' is not defined
Display the rolled result
image_rolled <- readImage(paste0(folder_green_rolled, image_name, "-02-rolled.tiff"))
display(image_rolled, method = "raster")

3. Thresholding
Here because the images have undergone gray scale and background
subtraction so I apply a global threshold to the image
threshold <- otsu(image_rolled)
image_thresholded <- image_rolled < threshold
display(image_thresholded, method = "raster")

4. Detect round shaped object and remove super small size
To select potential colonies: area, perimeter, and circularity.
This step is implemented here to prevent over segmentation and reduce
segmentation load
As you can see here, attached objects are not divided yet
image_object <- bwlabel(image_thresholded)
object_shape <- computeFeatures.shape(image_object) %>% as_tibble(rownames = "ObjectID")
object_shape_round <- object_shape %>%
# Area
filter(s.area > 800 & s.area < 20000) %>%
# Remove tape and label that has really large variation in radius
filter(s.radius.sd < 10) %>%
# # Roundness = 1 means a perfect circle
# mutate(Roundness = (s.radius.max - s.radius.min)/2) %>%
# filter(Roundness > 0.1 & Roundness < 50) %>%
# Circularity = 1 means a perfect circle and goes down to 0 for non-cicular shapes
mutate(Circularity = 4 * pi * s.area / s.perimeter^2) %>%
filter(Circularity > 0.3) %>%
arrange(desc(s.area))
object_ID_nonround <- which(!(object_shape$ObjectID %in% object_shape_round$ObjectID))
image_round <- rmObjects(image_object, object_ID_nonround, reenumerate = F)
display(colorLabels(image_round), method = "raster")

5. Distance map
The distance map contains for each pixel the distance to the nearest
background pixe
image_distancemap <- distmap(image_round)
display(normalize(image_distancemap), method = "raster")

6. Watershed
This is the actual segmentation step. Here the adjacent objects are
better distinguished
image_watershed <- watershed(image_distancemap, tolerance = 1)
display(colorLabels(image_watershed), method = "raster")

Output the example
# # writeImage(image_original, paste0(folder_main, "example/", image_name, "-00-original.tiff"))
# # writeImage(image_green, paste0(folder_main, "example/", image_name, "-01-green.tiff"))
# writeImage(image_rolled, paste0(folder_main, "example/", image_name, "-02-rolled.tiff"))
# writeImage(image_thresholded, paste0(folder_main, "example/", image_name, "-03-threshold.tiff"))
# #writeImage(colorLabels(image_object), paste0(folder_main, "example/", image_name, "-03a-object.tiff"))
# writeImage(image_round, paste0(folder_main, "example/", image_name, "-04-round_object.tiff"))
# writeImage(normalize(image_distancemap), paste0(folder_main, "example/", image_name, "-05-distance_map.tiff"))
# writeImage(colorLabels(image_watershed), paste0(folder_main, "example/", image_name, "-06-watershed.tiff"))
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiNrbml0cjo6b3B0c19jaHVuaygpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KEVCSW1hZ2UpCmxpYnJhcnkocmV0aWN1bGF0ZSkKZm9sZGVyX21haW4gPC0gIi9Vc2Vycy9jaGFuZy15dS9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3Jhdy9wbGF0ZV9zY2FuL2VtZXJnZW50X2NvZXhpc3RlbmNlX3BsYXRlX3NjYW5fY2hlY2svIgpgYGAKCgpFeGFtcGxlIHBhaXIgCgpEX1Q4X0MxUjJfMQpEX1Q4X0MxUjJfMiAKRF9UOF9DMVIyXzUtOTVfMV8yCgoKYGBge3J9Cmxpc3RfaW1hZ2VzIDwtIHRpYmJsZSgKICAgIGltYWdlX25hbWUgPSBjKCJEX1Q4X0MxUjJfMSIsICJEX1Q4X0MxUjJfMiIsICJEX1Q4X0MxUjJfNS05NV8xXzIiKSwKICAgIGZvbGRlcl9vcmlnaW5hbCA9IHJlcChwYXN0ZTAoZm9sZGVyX21haW4sICJjaGVjay9ELTAwLW9yaWdpbmFsLyIpLCAzKSwKICAgIGZvbGRlcl9ncmVlbiA9IHJlcChwYXN0ZTAoZm9sZGVyX21haW4sICJleGFtcGxlLyIpLCAzKSwKICAgIGZvbGRlcl9ncmVlbl9yb2xsZWQgPSByZXAocGFzdGUwKGZvbGRlcl9tYWluLCAiZXhhbXBsZS8iKSwgMyksCiAgICBmb2xkZXJfZ3JlZW5fd2F0ZXJzaGVkID0gcmVwKHBhc3RlMChmb2xkZXJfbWFpbiwgImV4YW1wbGUvIiksIDMpLAogICAgZm9sZGVyX2dyZWVuX2ZlYXR1cmUgPSByZXAocGFzdGUwKGZvbGRlcl9tYWluLCAiZXhhbXBsZS8iKSwgMyksCiAgICBmb2xkZXJfZ3JlZW5fY2x1c3RlciA9IHJlcChwYXN0ZTAoZm9sZGVyX21haW4sICJleGFtcGxlLyIpLCAzKQopCgoKaSA9IDMKaW1hZ2VfbmFtZSA8LSBsaXN0X2ltYWdlcyRpbWFnZV9uYW1lW2ldCmZvbGRlcl9vcmlnaW5hbCA8LSBsaXN0X2ltYWdlcyRmb2xkZXJfb3JpZ2luYWxbaV0KZm9sZGVyX2dyZWVuIDwtIGxpc3RfaW1hZ2VzJGZvbGRlcl9ncmVlbltpXQpmb2xkZXJfZ3JlZW5fcm9sbGVkIDwtIGxpc3RfaW1hZ2VzJGZvbGRlcl9ncmVlbl9yb2xsZWRbaV0KZm9sZGVyX2dyZWVuX3dhdGVyc2hlZCA8LSBsaXN0X2ltYWdlcyRmb2xkZXJfZ3JlZW5fd2F0ZXJzaGVkW2ldCmZvbGRlcl9ncmVlbl9mZWF0dXJlIDwtIGxpc3RfaW1hZ2VzJGZvbGRlcl9ncmVlbl9mZWF0dXJlW2ldCmBgYAoKIyAwLiBvcmlnaW5hbCBpbWFnZQoKYGBge3J9CmltYWdlX29yaWdpbmFsIDwtIHJlYWRJbWFnZShwYXN0ZTAoZm9sZGVyX29yaWdpbmFsLCBpbWFnZV9uYW1lLCAiLnRpZmYiKSkKd3JpdGVJbWFnZShpbWFnZV9vcmlnaW5hbCwgcGFzdGUwKGZvbGRlcl9ncmVlbiwgaW1hZ2VfbmFtZSwgIi0wMC1vcmlnaW5hbC50aWZmIikpCmRpc3BsYXkoaW1hZ2Vfb3JpZ2luYWwsIG1ldGhvZCA9ICJyYXN0ZXIiKQpgYGAKCiMgMS4gR3JlZW4gY2hhbm5lbAoKYGBge3J9CnRlbXAgPC0gaW1hZ2Vfb3JpZ2luYWwKY29sb3JNb2RlKHRlbXApID0gR3JheXNjYWxlCmltYWdlX2dyZWVuIDwtIHRlbXBbLCwyXQp3cml0ZUltYWdlKGltYWdlX2dyZWVuLCBwYXN0ZTAoZm9sZGVyX2dyZWVuLCBpbWFnZV9uYW1lLCAiLTAxLWdyZWVuLnRpZmYiKSkKZGlzcGxheShpbWFnZV9ncmVlbiwgbWV0aG9kID0gInJhc3RlciIpCmBgYAoKCgojIDIuIFJvbGxpbmcgYmFsbAoKUHl0aG9uIGNvZGUgZnJvbSBgcm9sbGluZ19iYWxsLnB5YAoKYGBge3J9CnB5JGZpbGVfZ3JlZW4gPC0gcGFzdGUwKGZvbGRlcl9ncmVlbiwgaW1hZ2VfbmFtZSwgIi50aWZmIikKcHkkZmlsZV9ncmVlbl9yb2xsZWQgPC0gcGFzdGUwKGZvbGRlcl9ncmVlbl9yb2xsZWQsIGltYWdlX25hbWUsICItMDItcm9sbGVkLnRpZmYiKQpgYGAKClRoZSBSIHZhcmlhYmxlcyBzaG91bGQgYmUgcGFzc2VkIHRvIHB5dGhvbiBidXQgc29tZWhvdyBmYWlsZWQuIE5vdCBzdXJlIHdoZXJlIHRoZSBwcm9ibGVtIGlzIGZyb20sIHByb2JhYmx5IHJldGljdWFsdGUuIDIwMjIwOTAyIHVzZSB0aGUgZXh0ZXJuYWxseSBnZW5lcmF0ZWQgcm9sbGVkIGltYWdlcy4KCmBgYHtweXRob259CmltcG9ydCBpbWFnZWlvCmltcG9ydCBvcwppbXBvcnQgc3lzCmltcG9ydCBza2ltYWdlCmZyb20gc2tpbWFnZSBpbXBvcnQgZGF0YSwgcmVzdG9yYXRpb24sIHV0aWwsIGlvLCBjb2xvcgoKZGVmIHJvbGxpbmdfYmFsbF9saWdodChpbWFnZSk6CiAgICAjIDIuIGludmVydCB0aGUgaW1hZ2UKICAgIGltYWdlX2ludmVydGVkID0gdXRpbC5pbnZlcnQoaW1hZ2UpCiAgICAKICAgICMgMy4gcm9sbGluZyBiYWxsCiAgICBiYWNrZ3JvdW5kX2ludmVydGVkID0gcmVzdG9yYXRpb24ucm9sbGluZ19iYWxsKGltYWdlX2ludmVydGVkLCByYWRpdXMgPSA4MCwgbnVtX3RocmVhZHMgPSAxMCkKICAgIAogICAgIyA0LiBpbnZlcnQgdGhlIHJlc3VsdAogICAgaW1hZ2Vfcm9sbGVkX2ludmVydGVkID0gaW1hZ2VfaW52ZXJ0ZWQgLSBiYWNrZ3JvdW5kX2ludmVydGVkCiAgICBpbWFnZV9yb2xsZWQgPSB1dGlsLmludmVydChpbWFnZV9yb2xsZWRfaW52ZXJ0ZWQpCiAgICByZXR1cm4gaW1hZ2Vfcm9sbGVkCiAgICAKaW1hZ2UgPSBpby5pbXJlYWQoZmlsZV9ncmVlbikKaW1hZ2Vfcm9sbGVkID0gcm9sbGluZ19iYWxsX2xpZ2h0KGltYWdlKQppby5pbXNhdmUoZmlsZV9ncmVlbl9yb2xsZWQsIGltYWdlX3JvbGxlZCkKYGBgCgpEaXNwbGF5IHRoZSByb2xsZWQgcmVzdWx0CgpgYGB7cn0KaW1hZ2Vfcm9sbGVkIDwtIHJlYWRJbWFnZShwYXN0ZTAoZm9sZGVyX2dyZWVuX3JvbGxlZCwgaW1hZ2VfbmFtZSwgIi0wMi1yb2xsZWQudGlmZiIpKQpkaXNwbGF5KGltYWdlX3JvbGxlZCwgbWV0aG9kID0gInJhc3RlciIpCmBgYAoKCgojIDMuIFRocmVzaG9sZGluZwoKSGVyZSBiZWNhdXNlIHRoZSBpbWFnZXMgaGF2ZSB1bmRlcmdvbmUgZ3JheSBzY2FsZSBhbmQgYmFja2dyb3VuZCBzdWJ0cmFjdGlvbiBzbyBJIGFwcGx5IGEgZ2xvYmFsIHRocmVzaG9sZCB0byB0aGUgaW1hZ2UKCmBgYHtyfQp0aHJlc2hvbGQgPC0gb3RzdShpbWFnZV9yb2xsZWQpCmltYWdlX3RocmVzaG9sZGVkIDwtIGltYWdlX3JvbGxlZCA8IHRocmVzaG9sZApkaXNwbGF5KGltYWdlX3RocmVzaG9sZGVkLCBtZXRob2QgPSAicmFzdGVyIikKYGBgCgojIDQuIERldGVjdCByb3VuZCBzaGFwZWQgb2JqZWN0IGFuZCByZW1vdmUgc3VwZXIgc21hbGwgc2l6ZQoKVG8gc2VsZWN0IHBvdGVudGlhbCBjb2xvbmllczogYXJlYSwgcGVyaW1ldGVyLCBhbmQgY2lyY3VsYXJpdHkuCgpUaGlzIHN0ZXAgaXMgaW1wbGVtZW50ZWQgaGVyZSB0byBwcmV2ZW50IG92ZXIgc2VnbWVudGF0aW9uIGFuZCByZWR1Y2Ugc2VnbWVudGF0aW9uIGxvYWQKCkFzIHlvdSBjYW4gc2VlIGhlcmUsIGF0dGFjaGVkIG9iamVjdHMgYXJlIG5vdCBkaXZpZGVkIHlldAoKYGBge3J9CmltYWdlX29iamVjdCA8LSBid2xhYmVsKGltYWdlX3RocmVzaG9sZGVkKQpvYmplY3Rfc2hhcGUgPC0gY29tcHV0ZUZlYXR1cmVzLnNoYXBlKGltYWdlX29iamVjdCkgJT4lIGFzX3RpYmJsZShyb3duYW1lcyA9ICJPYmplY3RJRCIpCgpvYmplY3Rfc2hhcGVfcm91bmQgPC0gb2JqZWN0X3NoYXBlICU+JQogICAgIyBBcmVhCiAgICBmaWx0ZXIocy5hcmVhID4gODAwICYgcy5hcmVhIDwgMjAwMDApICU+JQogICAgIyBSZW1vdmUgdGFwZSBhbmQgbGFiZWwgdGhhdCBoYXMgcmVhbGx5IGxhcmdlIHZhcmlhdGlvbiBpbiByYWRpdXMKICAgIGZpbHRlcihzLnJhZGl1cy5zZCA8IDEwKSAlPiUKICAgICMgIyBSb3VuZG5lc3MgPSAxIG1lYW5zIGEgcGVyZmVjdCBjaXJjbGUKICAgICMgbXV0YXRlKFJvdW5kbmVzcyA9IChzLnJhZGl1cy5tYXggLSBzLnJhZGl1cy5taW4pLzIpICU+JQogICAgIyBmaWx0ZXIoUm91bmRuZXNzID4gMC4xICYgUm91bmRuZXNzIDwgNTApICU+JQogICAgIyBDaXJjdWxhcml0eSA9IDEgbWVhbnMgYSBwZXJmZWN0IGNpcmNsZSBhbmQgZ29lcyBkb3duIHRvIDAgZm9yIG5vbi1jaWN1bGFyIHNoYXBlcwogICAgbXV0YXRlKENpcmN1bGFyaXR5ID0gNCAqIHBpICogcy5hcmVhIC8gcy5wZXJpbWV0ZXJeMikgJT4lCiAgICBmaWx0ZXIoQ2lyY3VsYXJpdHkgPiAwLjMpICU+JQogICAgYXJyYW5nZShkZXNjKHMuYXJlYSkpCm9iamVjdF9JRF9ub25yb3VuZCA8LSB3aGljaCghKG9iamVjdF9zaGFwZSRPYmplY3RJRCAlaW4lIG9iamVjdF9zaGFwZV9yb3VuZCRPYmplY3RJRCkpCgppbWFnZV9yb3VuZCA8LSBybU9iamVjdHMoaW1hZ2Vfb2JqZWN0LCBvYmplY3RfSURfbm9ucm91bmQsIHJlZW51bWVyYXRlID0gRikKZGlzcGxheShjb2xvckxhYmVscyhpbWFnZV9yb3VuZCksIG1ldGhvZCA9ICJyYXN0ZXIiKQpgYGAKCiMgNS4gRGlzdGFuY2UgbWFwCgpUaGUgZGlzdGFuY2UgbWFwIGNvbnRhaW5zIGZvciBlYWNoIHBpeGVsIHRoZSBkaXN0YW5jZSB0byB0aGUgbmVhcmVzdCBiYWNrZ3JvdW5kIHBpeGUKCgpgYGB7cn0KaW1hZ2VfZGlzdGFuY2VtYXAgPC0gZGlzdG1hcChpbWFnZV9yb3VuZCkKZGlzcGxheShub3JtYWxpemUoaW1hZ2VfZGlzdGFuY2VtYXApLCBtZXRob2QgPSAicmFzdGVyIikKYGBgCgoKCgoKIyA2LiBXYXRlcnNoZWQKClRoaXMgaXMgdGhlIGFjdHVhbCBzZWdtZW50YXRpb24gc3RlcC4gSGVyZSB0aGUgYWRqYWNlbnQgb2JqZWN0cyBhcmUgYmV0dGVyIGRpc3Rpbmd1aXNoZWQKCmBgYHtyfQppbWFnZV93YXRlcnNoZWQgPC0gd2F0ZXJzaGVkKGltYWdlX2Rpc3RhbmNlbWFwLCB0b2xlcmFuY2UgPSAxKQpkaXNwbGF5KGNvbG9yTGFiZWxzKGltYWdlX3dhdGVyc2hlZCksIG1ldGhvZCA9ICJyYXN0ZXIiKQpgYGAKCgoKIyBPdXRwdXQgdGhlIGV4YW1wbGUKCmBgYHtyfQojICMgd3JpdGVJbWFnZShpbWFnZV9vcmlnaW5hbCwgcGFzdGUwKGZvbGRlcl9tYWluLCAiZXhhbXBsZS8iLCBpbWFnZV9uYW1lLCAiLTAwLW9yaWdpbmFsLnRpZmYiKSkKIyAjIHdyaXRlSW1hZ2UoaW1hZ2VfZ3JlZW4sIHBhc3RlMChmb2xkZXJfbWFpbiwgImV4YW1wbGUvIiwgaW1hZ2VfbmFtZSwgIi0wMS1ncmVlbi50aWZmIikpCiMgd3JpdGVJbWFnZShpbWFnZV9yb2xsZWQsIHBhc3RlMChmb2xkZXJfbWFpbiwgImV4YW1wbGUvIiwgaW1hZ2VfbmFtZSwgIi0wMi1yb2xsZWQudGlmZiIpKQojIHdyaXRlSW1hZ2UoaW1hZ2VfdGhyZXNob2xkZWQsIHBhc3RlMChmb2xkZXJfbWFpbiwgImV4YW1wbGUvIiwgaW1hZ2VfbmFtZSwgIi0wMy10aHJlc2hvbGQudGlmZiIpKQojICN3cml0ZUltYWdlKGNvbG9yTGFiZWxzKGltYWdlX29iamVjdCksIHBhc3RlMChmb2xkZXJfbWFpbiwgImV4YW1wbGUvIiwgaW1hZ2VfbmFtZSwgIi0wM2Etb2JqZWN0LnRpZmYiKSkKIyB3cml0ZUltYWdlKGltYWdlX3JvdW5kLCBwYXN0ZTAoZm9sZGVyX21haW4sICJleGFtcGxlLyIsIGltYWdlX25hbWUsICItMDQtcm91bmRfb2JqZWN0LnRpZmYiKSkKIyB3cml0ZUltYWdlKG5vcm1hbGl6ZShpbWFnZV9kaXN0YW5jZW1hcCksIHBhc3RlMChmb2xkZXJfbWFpbiwgImV4YW1wbGUvIiwgaW1hZ2VfbmFtZSwgIi0wNS1kaXN0YW5jZV9tYXAudGlmZiIpKQojIHdyaXRlSW1hZ2UoY29sb3JMYWJlbHMoaW1hZ2Vfd2F0ZXJzaGVkKSwgcGFzdGUwKGZvbGRlcl9tYWluLCAiZXhhbXBsZS8iLCBpbWFnZV9uYW1lLCAiLTA2LXdhdGVyc2hlZC50aWZmIikpCmBgYAoKCgoKCgoKCgoKCgo=